/**
 * 就这美 2017
 */
package com.xjoyt.pay.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/**
 * 
 * @版权：就这美 版权所有 (c) 2017
 * @ClassName:SignUtil
 * @author liangzhm<br/>
 * @email liangzhm1985@foxmail.com
 * @version Revision 1.0.0
 * @since JDK 1.7
 * @创建日期：2017年5月6日下午5:33:54
 * @功能说明：
 * 
 */
public class SignUtil {

	private static final Logger logger = Logger.getLogger(SignUtil.class);

	private static final String SIGN = "sign";

	private static final String PL_SIGN = "pl_sign";

	private static final String CHARSET_DEFAULT = "UTF-8";

	/**
	 * 签名 sign
	 * 
	 * @author liangzhm
	 * @param params
	 * @param key
	 * @return
	 * @创建日期：2017年5月11日下午1:36:37
	 */
	public static String sign(Map<String, String> params, String key) {
		if (params.containsKey(SIGN)) {
			params.remove(SIGN);
		}
		if (params.containsKey(PL_SIGN)) {
			params.remove(PL_SIGN);
		}
		StringBuilder buf = new StringBuilder((params.size() + 1) * 10);
		buildPayParams(buf, params, false);
		logger.debug("签名前数据"+buf.toString());
		buf.append(key);
		String preStr = buf.toString();
		return encrypt2MD5(preStr);// MD5.sign(preStr, CHARSET_DEFAULT);
	}

	/**
	 * 验签 checkSign
	 * 
	 * @author liangzhm
	 * @param SortedMap
	 * @param md5Key
	 * @return
	 * @创建日期：2017年5月6日下午5:34:29
	 */
	public static boolean checkSign(Map<String, String> params, String key) {
		boolean result = false;
		if (params.containsKey(SIGN)) {
			String sign = params.get(SIGN);
			params.remove(SIGN);
			String signRecieve = sign(params, key);
			result = sign.equalsIgnoreCase(signRecieve);
		}
		return result;
	}

	/**
	 * 根据入参，构造待签名串 buildPayParams
	 * 
	 * @author liangzhm
	 * @param sb
	 * @param payParams
	 * @param encoding
	 * @创建日期：2017年5月6日下午6:52:23
	 */
	public static void buildPayParams(StringBuilder sb, Map<String, String> payParams, boolean encoding) {
		List<String> keys = new ArrayList<String>(payParams.keySet());
		Collections.sort(keys);
		String value;
		for (String key : keys) {
			value = payParams.get(key);
			if (StringUtils.isEmpty(value)) {
				continue;
			}
			if (encoding) {
				sb.append(urlEncode(value));
			} else {
				sb.append(value);
			}
		}
	}

	/**
	 * 参数编码 urlEncode
	 * 
	 * @author liangzhm
	 * @param str
	 * @param encoding
	 * @return
	 * @创建日期：2017年5月6日下午6:48:49
	 */
	public static String urlEncode(String str, String encoding) {
		try {
			return URLEncoder.encode(str, encoding);
		} catch (Throwable e) {
			return str;
		}
	}

	/**
	 * 参数编码 urlEncode
	 * 
	 * @author liangzhm
	 * @param str
	 * @return
	 * @创建日期：2017年5月6日下午6:48:54
	 */
	public static String urlEncode(String str) {
		try {
			return URLEncoder.encode(str, CHARSET_DEFAULT);
		} catch (Throwable e) {
			return str;
		}
	}

	public static String encrypt2MD5(String originstr) {
		String result = null;
		// 用来将字节转换成 16 进制表示的字符
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		if (originstr != null && !"".equals(originstr)) {
			try {
				// 返回实现指定摘要算法的 MessageDigest 对象
				MessageDigest md = MessageDigest.getInstance("MD5");
				// 使用utf-8编码将originstr字符串编码并保存到source字节数组
				byte[] source = originstr.getBytes("utf-8");
				// 使用指定的 byte 数组更新摘要
				md.update(source);
				// 通过执行诸如填充之类的最终操作完成哈希计算,结果是一个128位的长整数
				byte[] tmp = md.digest();
				// 用16进制数表示需要32位
				char[] str = new char[32];
				for (int i = 0, j = 0; i < 16; i++) {
					// j表示转换结果中对应的字符位置
					// 从第一个字节开始,对 MD5 的每一个字节
					// 转换成 16 进制字符
					byte b = tmp[i];

					// 取字节中高 4 位的数字转换
					// 无符号右移运算符>>> ,它总是在左边补0
					// 0x代表它后面的是十六进制的数字. f转换成十进制就是15
					str[j++] = hexDigits[b >>> 4 & 0xf];

					// 取字节中低 4 位的数字转换
					str[j++] = hexDigits[b & 0xf];
				}

				// 结果转换成字符串用于返回
				result = new String(str);

			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}

		}

		return result;
	}
}
